package turritopsis

import (
	"ebbflow/pkg/adkr"
	"log"
	"time"
)





// SDumboACSConfig represents configuration for sDumbo ACS
type SDumboACSConfig struct {
	N           int           // Number of nodes
	F           int           // Number of faulty nodes
	NetworkDelay time.Duration // Network delay simulation
	ConsensusDelay time.Duration // Consensus processing delay
    BatchSize   int           // Initial batch size (transactions per epoch)
    Adaptive    bool          // Enable simple adaptive batch tuning
}

// SDumboACS implements a realistic sDumbo ACS simulation
type SDumboACS struct {
	config SDumboACSConfig
	logger *log.Logger
    batchSize int
}

// NewSDumboACS creates a new sDumbo ACS instance
func NewSDumboACS(config SDumboACSConfig, logger *log.Logger) *SDumboACS {
	if logger == nil {
		logger = log.Default()
	}
    bs := config.BatchSize
    if bs <= 0 { bs = 1000 }
    return &SDumboACS{config: config, logger: logger, batchSize: bs}
}

// RunACS executes the sDumbo ACS protocol
func (acs *SDumboACS) RunACS(sid string, input []byte) ([][]byte, error) {
	acs.logger.Printf("sDumbo ACS[%s]: Starting consensus with N=%d, F=%d", sid, acs.config.N, acs.config.F)
    start := time.Now()
	
	// Phase 1: VAL - Broadcast input (if any)
	if input != nil {
		valDelay := acs.config.NetworkDelay + time.Duration(rand.Intn(10))*time.Millisecond
		time.Sleep(valDelay)
		acs.logger.Printf("sDumbo ACS[%s]: VAL phase completed", sid)
	}
	
	// Phase 2: ECHO - Echo received values
	echoDelay := acs.config.NetworkDelay + time.Duration(rand.Intn(20))*time.Millisecond
	time.Sleep(echoDelay)
	acs.logger.Printf("sDumbo ACS[%s]: ECHO phase completed", sid)
	
	// Phase 3: READY - Ready for output
	readyDelay := acs.config.NetworkDelay + time.Duration(rand.Intn(15))*time.Millisecond
	time.Sleep(readyDelay)
	acs.logger.Printf("sDumbo ACS[%s]: READY phase completed", sid)
	
	// Phase 4: OUTPUT - Decide on common subset
	outputDelay := acs.config.ConsensusDelay + time.Duration(rand.Intn(30))*time.Millisecond
	time.Sleep(outputDelay)
	
    // Generate transactions for this epoch (batch size configurable/adaptive)
    txCount := acs.batchSize
	transactions := acs.generateTransactions(txCount)
	
	acs.logger.Printf("sDumbo ACS[%s]: OUTPUT phase completed, decided %d transactions", sid, len(transactions))
    // Simple adaptive batch tuning for next epoch
    if acs.config.Adaptive {
        dur := time.Since(start)
        // target window ~80..150ms for ACS portion (coarse)
        if dur < 80*time.Millisecond {
            // increase by 15%
            acs.batchSize = int(float64(acs.batchSize) * 1.15)
        } else if dur > 150*time.Millisecond {
            // decrease by 15%
            acs.batchSize = int(float64(acs.batchSize) * 0.85)
        }
        if acs.batchSize < 100 { acs.batchSize = 100 }
        if acs.batchSize > 5000 { acs.batchSize = 5000 }
        acs.logger.Printf("sDumbo ACS[%s]: adaptive next batch_size=%d (dur=%v)", sid, acs.batchSize, dur)
    }
	
	return transactions, nil
}

// generateTransactions creates a batch of 250-byte transactions
func (acs *SDumboACS) generateTransactions(count int) [][]byte {
	transactions := make([][]byte, count)
	for i := 0; i < count; i++ {
		// Generate 250 bytes of random data
		data := make([]byte, 250)
		rand.Read(data)
		
		// Create transaction with ID and data
		txID := fmt.Sprintf("TX_%d_", i)
		txData := append([]byte(txID), data...)
		transactions[i] = txData
	}
	return transactions
}

// CreateSDumboACSFunc creates a function compatible with ACSFunc interface
func CreateSDumboACSFunc(config SDumboACSConfig, logger *log.Logger) ACSFunc {
	acs := NewSDumboACS(config, logger)
	return acs.RunACS
}
